
#ifndef RELIEVE_H_
#define RELIEVE_H_

#include "superficie.h"

class Generador;
class Superficie;

class Relieve : public Superficie {
   private:
      Generador &ruidoOffset;
      Superficie &base;

      const float scaleX;
      const float scaleY;
 
      const float dx;
      const float dy;

   public: 
      /*
       * Construye una Superficie basada en los resultados retornados
       * por el generador "ruidoOffset", y la coordenada z retornada por la
       * superficie "base".
       *
       * Dado que la interfaz del Generador requiere ser evaluada en 
       * un plano (x, y), es necesario hacer un mapeo entre
       * las coordenadas (u, v) del metodo operator() y el espacion (x, y) 
       * del Generador.
       * Para ello, se definen los valores de escala para X y para Y
       * donde se cumplen que
       *    
       *    0 < scaleX
       *    0 < scaleY
       *
       * El mapeo resulta ser
       *
       *    x = u * scaleX
       *    y = v * scaleY
       *
       * La superficie resultante es igual, coordenada a coordenada
       * Siendo
       *
       *    z = base(u, v) 
       *    r = ruidoOffset(x, y)
       *
       * La normal exacta, de orden 2 es
       *
       *    N + Z_u x R_y + R_x x Z_v + N_d
       *
       * Donde N es la normal de la "base"
       *       Z_u, Z_v es la diferencia de los Z de la "base" 
       *                variando el eje u v.
       *       R_x, R_y es la diferencia de los ruidos R retornados
       *                por "ruidoOffset" variando el eje x y.
       *
       * Se efectua una simplificacion, relativamente valida
       * para valores chicos y similares en R_x y R_y 
       * y para valores de Z_u y Z_v similares:
       *
       *    N + Z_u x R_y + R_x x Z_v + N_d   =
       *    N + Z_u x R_y + R_x x Z_u + N_d   =   (Z_u = Z_v)
       *    N + Z_u x (R_y - R_x) + N_d       =
       *    N + Z_u x (R_x - R_x) + N_d       =   (R_x = R_y)
       *    N + Z_u x 0 + N_d                 =
       *    N + N_d
       *
       * Donde N_d es calculador como
       *
       *    (ruidoOffset(x + dx, y) - ruidoOffset(x - dx, y))
       *       * 
       *    (ruidoOffset(x, y + dy) - ruidoOffset(x, y - dy))
       *
       *
       * La superficie "base" es apropiada por esta clase y los recurso
       * seran liberados
       *
       * */
      Relieve(Generador &ruidoOffset, Superficie &base, 
            float scaleX, float scaleY,
            float dx, float dy);

      virtual Coord operator()(float u, float v) const;
      virtual Coord normal(float u, float v) const;

      ~Relieve();
};

#endif
